package xyz.icxl.android.architecture.data.net.okhttp

import android.util.Log
import com.blankj.utilcode.util.*
import com.tencent.mmkv.MMKV
import xyz.icxl.android.architecture.data.net.okhttp.body.ProgressResponseForDownloadBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.asRequestBody
import xyz.icxl.android.architecture.data.net.okhttp.body.ProgressResponseForUploadBody
import xyz.icxl.android.architecture.data.net.okhttp.interceptors.HeaderInterceptor
import xyz.icxl.android.architecture.data.net.okhttp.interceptors.PublicParameterInterceptor
import xyz.icxl.android.architecture.helper.MoshiHelper
import xyz.icxl.kotlion.ext.primitives.getInputStreamType
import java.io.*
import java.net.URL
import java.net.URLEncoder
import java.util.concurrent.TimeUnit

/**
 * 文件描述：基础的网络接口
 * 文件创建人：ChenXinLei
 * 文件创建人联系方式：502616659(QQ)
 * 创建时间：2020 年 08月 25 日
 * 文件版本：v1.0
 * 版本描述：创建文件
 */
abstract class BaseNetworkApi {
    open val connectTimeout = 10L
    open val readTimeout = 10L
    open val writeTimeout = 10L
    open val callTimeout = 10L
    private val head = "BaseNetworkApi.head"
    protected abstract val uploadFileServerUrl: String

    private val uploadOrDownloadClint: OkHttpClient by lazy {
        OkHttpClient.Builder()
            .connectTimeout(connectTimeout, TimeUnit.SECONDS)
            .readTimeout(readTimeout, TimeUnit.SECONDS)
            .writeTimeout(writeTimeout, TimeUnit.SECONDS)
            .callTimeout(callTimeout, TimeUnit.SECONDS)
            .addInterceptor(headInterceptor)
            .build()
    }

    @Throws(IOException::class)
    fun uploadFile(parameterName: String, file: File, l: ProgressListener): String? {
        val mediaType = "multipart/form-data; charset=utf-8".toMediaTypeOrNull()
        val fileBody = file.asRequestBody(mediaType)
        val requestBody = MultipartBody.Builder()
            .setType(mediaType!!)
            .apply {
                getPublicParameter().forEach { entry ->
                    addFormDataPart(entry.key, entry.value)
                }
            }
            .addFormDataPart(
                parameterName, file.absolutePath.substring(
                    file.absolutePath.lastIndexOf(
                        "/"
                    )
                ), ProgressResponseForUploadBody(fileBody, l)
            )
            .build()
        return uploadOrDownloadClint.newCall(
            Request.Builder().method("GET",requestBody).url(
                uploadFileServerUrl
            ).build()
        ).execute().body?.string()
    }

    fun downloadFile(url: String, saveDir: String,fileName:String, l: ProgressListener?): String {
        val request = Request.Builder().url(url).build()
        val response = OkHttpClient.Builder()
            .connectTimeout(connectTimeout, TimeUnit.SECONDS)
            .readTimeout(readTimeout, TimeUnit.SECONDS)
            .writeTimeout(writeTimeout, TimeUnit.SECONDS)
            .callTimeout(callTimeout, TimeUnit.SECONDS)
            .addInterceptor(publicParameterInterceptor)
            .addNetworkInterceptor {
                val response = it.proceed(it.request())
                val body = response.body ?: return@addNetworkInterceptor response
                val pBody = ProgressResponseForDownloadBody(body, l)
                response.newBuilder()
                    .body(pBody)
                    .build()
            }
            .build()
            .newCall(request)
            .execute()
        if (response.isSuccessful) {
            val srcInputStream = response.body?.byteStream()
//            val tempFile = File(
//                saveDir,
//                "${System.currentTimeMillis()}.${srcInputStream?.getInputStreamType() ?: ""}"
//            )
            val tempFile = File(
                saveDir,
                fileName
            )
            val dir: File? = tempFile.parentFile
            if (dir?.exists() == false) {
                dir.mkdirs()
            }
            if (!tempFile.exists()) {
                tempFile.createNewFile()
            }
            if (srcInputStream == null) {
                return ""
            }
            val fos = FileOutputStream(tempFile)
            fos.write(srcInputStream.readBytes())
            fos.flush()
            fos.close()
            srcInputStream.close()
            Log.i("下载地址", "downloadFile:${tempFile.absolutePath} ")
            return tempFile.absolutePath
        } else {
         ToastUtils.showLong("网络错误")
            return  ""
        }

    }

    protected val headInterceptor = HeaderInterceptor(getHeaderParameter = { currentHeadParameter })

    val currentHeadParameter: HashMap<String, String> by lazy {
        val data = MMKV.defaultMMKV().decodeString(head, "{}")
        val hashMap = HashMap<String,String>(MoshiHelper.toMutableMap(String::class.java,String::class.java,data?:"{}"))
        try {
            if (hashMap["platform"].isNullOrEmpty())
                hashMap["platform"] = "Android"
            if (hashMap["systemName"].isNullOrEmpty())
                hashMap["systemName"] = "android"
            if (hashMap["systemVersion"].isNullOrEmpty())
                hashMap["systemVersion"] = DeviceUtils.getSDKVersionName()
            if (hashMap["phoneType"].isNullOrEmpty())
                hashMap["phoneType"] = DeviceUtils.getManufacturer() + "-" + DeviceUtils.getModel()
            hashMap["versionName"] = AppUtils.getAppVersionName()
            if (hashMap["versionCode"].isNullOrEmpty())
                hashMap["versionCode"] = AppUtils.getAppVersionCode().toString()
            if (hashMap["packageName"].isNullOrEmpty())
                hashMap["packageName"] = AppUtils.getAppPackageName()
            if (hashMap["isDebug"].isNullOrEmpty())
                hashMap["isDebug"] = AppUtils.isAppDebug().toString()
            if (hashMap["deviceOtherInfo"].isNullOrEmpty()) {
                val sb = StringBuilder()
                sb.append("tablet:${DeviceUtils.isTablet()}").append(",")
                sb.append("ABIs:${MoshiHelper.toJsonStr(DeviceUtils.getABIs())}").append(",")
                sb.append("rooted:${DeviceUtils.isDeviceRooted()}").append(",")
                sb.append("androidId:${DeviceUtils.getAndroidID()}").append(",")
                sb.append("emulator:${DeviceUtils.isEmulator()}").append(",")
                sb.append("uniqueDeviceId:${DeviceUtils.getUniqueDeviceId()}").append(",")
                sb.append("simType:${PhoneUtils.getSimOperatorByMnc()}").append(",")
                sb.append("roomInfo:${RomUtils.getRomInfo()}").append(",")
                hashMap["deviceOtherInfo"] = URLEncoder.encode(sb.toString(), "UTF-8")
            }
            hashMap["lang"] = "en_lang"
        } catch (e: Exception) {
        }
        hashMap
    }

    /**
     * 添加请求头参数
     */
    fun addHeadParameter(key: String, value: String): Boolean {
        currentHeadParameter[key] = value
        return MMKV.defaultMMKV()!!.encode(head, GsonUtils.toJson(currentHeadParameter))
    }

    private val publicParameterInterceptor =
        PublicParameterInterceptor(getParameter = { getPublicParameter() })

    open fun getPublicParameter(): HashMap<String, String> {
        //parameter.put("appId", EncryptUtils.encryptMD5ToString(DeviceUtils.getAndroidID()))
        return HashMap()
    }

    fun downloadFileNoOkHttp(saveDir: String): String {
        val url = URL("https://pics1.baidu.com/feed/8694a4c27d1ed21b6d47772234ffb6cc53da3f80.jpeg?token=b4daccbe73d0eef5649b592be99040bd")
        val connection = url.openConnection()
        val inputStream: InputStream = connection.getInputStream()
        val bis = BufferedInputStream(inputStream)
        val imageFilePath = File(saveDir,"${System.currentTimeMillis()}.${inputStream.getInputStreamType()}")
        val fos = FileOutputStream(imageFilePath)
        val buffer = ByteArray(1024)
        var read: Int
        while (bis.read(buffer).also { read = it } > 0) {
            fos.write(buffer, 0, read)
        }
        fos.flush()
        fos.close()
        bis.close()
        inputStream.close()
        return imageFilePath.absolutePath
    }

}